/*!
 * @file       apm32f10x_dma.c
 *
 * @brief      This file provides all the DMA firmware functions
 *
 * @version    V1.0.0
 *
 * @date       2019-8-6
 *
 */

#include "apm32f10x_dma.h"

/*!
 * @brief     Reset the DMAx Channely registers to their default reset
 *
 * @param     DMAx_Channely:DMA1 channel(1 to 7) or DMA2 channel(1 to 5)
 *
 * @retval    None
 *
 * @note
 */
void DMA_Reset(DMA_Channel_T *DMAx_Channely)
{
    DMAx_Channely->SRC_B.EN = BIT_RESET;
    DMAx_Channely->SRC = 0;
    DMAx_Channely->CNTTC = 0;
    DMAx_Channely->MAC = 0;
    DMAx_Channely->PAC = 0;

    if(DMAx_Channely == DMA1_Channel1)
    {
        DMA1->IFR |= 0xFFFFFFF0;
    }
    else if(DMAx_Channely == DMA1_Channel2)
    {
        DMA1->IFR |= 0xFFFFFF0F;
    }
    else if(DMAx_Channely == DMA1_Channel3)
    {
        DMA1->IFR |= 0xFFFFF0FF;
    }
    else if(DMAx_Channely == DMA1_Channel4)
    {
        DMA1->IFR |= 0xFFFF0FFF;
    }
    else if(DMAx_Channely == DMA1_Channel5)
    {
        DMA1->IFR |= 0xFFF0FFFF;
    }
    else if(DMAx_Channely == DMA1_Channel6)
    {
        DMA1->IFR |= 0xFF0FFFFF;
    }
    else if(DMAx_Channely == DMA1_Channel7)
    {
        DMA1->IFR |= 0xF0FFFFFF;
    }
    else if(DMAx_Channely == DMA2_Channel1)
    {
        DMA2->IFR |= 0xFFFFFFF0;
    }
    else if(DMAx_Channely == DMA2_Channel2)
    {
        DMA2->IFR |= 0xFFFFFF0F;
    }
    else if(DMAx_Channely == DMA2_Channel3)
    {
        DMA2->IFR |= 0xFFFFF0FF;
    }
    else if(DMAx_Channely == DMA2_Channel4)
    {
        DMA2->IFR |= 0xFFFF0FFF;
    }
    else if(DMAx_Channely == DMA2_Channel5)
    {
        DMA2->IFR |= 0xFFF0FFFF;
    }
}

/*!
 * @brief     Configuration DMA channel through a structure
 *
 * @param     DMAx_Channely:DMA1 channel(1 to 7) or DMA2 channel(1 to 5)
 *
 * @param     DMA_ConfigStruct:Configuration structure
 *
 * @retval    None
 *
 * @note
 */
void DMA_Config(DMA_Channel_T* DMAx_Channely, DMA_Config_T* DMA_ConfigStruct)
{
    DMAx_Channely->SRC_B.DOT = DMA_ConfigStruct->DOT;
    DMAx_Channely->SRC_B.LOOP = DMA_ConfigStruct->DMA_LoopMode;
    DMAx_Channely->SRC_B.PLOOP = DMA_ConfigStruct->PLoop;
    DMAx_Channely->SRC_B.MLOOP = DMA_ConfigStruct->MLoop;
    DMAx_Channely->SRC_B.PWID = DMA_ConfigStruct->PeripheralDataSize;
    DMAx_Channely->SRC_B.MWID = DMA_ConfigStruct->MemoryDataSize;
    DMAx_Channely->SRC_B.PL = DMA_ConfigStruct->DMA_Priority;
    DMAx_Channely->SRC_B.M2MEN = DMA_ConfigStruct->M2M;

    DMAx_Channely->CNTTC = DMA_ConfigStruct->BufferSize;
    DMAx_Channely->PAC = DMA_ConfigStruct->PeripheralBaseAddr;
    DMAx_Channely->MAC = DMA_ConfigStruct->MemoryBaseAddr;
}

/*!
 * @brief     Populate the structure with default values
 *
 * @param     DMA_ConfigStruct:Configuration structure
 *
 * @retval    None
 *
 * @note
 */
void DMA_StructInit( DMA_Config_T* DMA_ConfigStruct)
{
    DMA_ConfigStruct->PeripheralBaseAddr = 0;
    DMA_ConfigStruct->MemoryBaseAddr = 0;
    DMA_ConfigStruct->DOT = DMA_DOT_PERIPHERAL_SRC;
    DMA_ConfigStruct->BufferSize = 0;
    DMA_ConfigStruct->PLoop = DMA_PERIPHERAL_LOOP_DISABLE;
    DMA_ConfigStruct->MLoop = DMA_MEMORY_LOOP_DISABLE;
    DMA_ConfigStruct->PeripheralDataSize = DMA_PERIPHERAL_DATA_SIZE_BYTE;
    DMA_ConfigStruct->MemoryDataSize = DMA_MEMORY_DATA_SIZE_BYTE;
    DMA_ConfigStruct->DMA_LoopMode = DMA_MODE_NORMAL;
    DMA_ConfigStruct->DMA_Priority = DMA_PRIORITY_LOW;
    DMA_ConfigStruct->M2M = DMA_M2MEN_DISABLE;
}

/*!
 * @brief     Enable the DMAx Channely
 *
 * @param     DMAx_Channely:DMA1 channel(1 to 7) or DMA2 channel(1 to 5)
 *
 * @retval    None
 *
 * @note
 */
void DMA_ENABLE(DMA_Channel_T *DMAx_Channely)
{
    DMAx_Channely->SRC_B.EN = ENABLE;
}

/*!
 * @brief     Disable the DMAx Channely
 *
 * @param     DMAx_Channely:DMA1 channel(1 to 7) or DMA2 channel(1 to 5)
 *
 * @retval    None
 *
 * @note
 */
void DMA_DISABLE(DMA_Channel_T *DMAx_Channely)
{
    DMAx_Channely->SRC_B.EN = DISABLE;
}

/*!
 * @brief     Enables the DMAx Channely interrupts.
 *
 * @param     DMAx_Channely:DMA1 channel(1 to 7) or DMA2 channel(1 to 5)
 *
 * @param     DMA_interrupus: DMA interrupts sources to selsct
 *
 * @retval    None
 *
 * @note
 */
void DMA_IntEnable(DMA_Channel_T *DMAx_Channely, DMA_IT DMA_interrupus)
{
    DMAx_Channely->SRC |= DMA_interrupus;
}

/*!
 * @brief     Disable the DMAx Channely interrupts.
 *
 * @param     DMAx_Channely:DMA1 channel(1 to 7) or DMA2 channel(1 to 5)
 *
 * @param     DMA_interrupus: DMA interrupts sources to selsct
 *
 * @retval    None
 *
 * @note
 */
void DMA_IntDisable(DMA_Channel_T *DMAx_Channely, DMA_IT DMA_interrupus)
{
    DMAx_Channely->SRC &= ~DMA_interrupus;
}

/*!
 * @brief     Sets the number of data units in the channel
 *
 * @param     DMAx_Channely:DMA1 channel(1 to 7) or DMA2 channel(1 to 5)
 *
 * @param     dataNumber:The number of data units in the current DMAx Channely transfer.
 *
 * @retval    None
 *
 * @note
 */
void DMA_SetCurrDataCounter(DMA_Channel_T *DMAx_Channely, uint16_t dataNumber)
{
    DMAx_Channely->CNTTC = dataNumber;
}

/*!
 * @brief     Read the number of data units in the channel
 *
 * @param     DMAx_Channely:DMA1 channel(1 to 7) or DMA2 channel(1 to 5)
 *
 * @retval    The number of CNTTC value
 *
 * @note
 */
uint16_t DMA_ReadCurrDataCounter(DMA_Channel_T *DMAx_Channely)
{
    return DMAx_Channely->CNTTC;
}

/*!
 * @brief     Read whether the specified DMAx Channely flag is set or not.
 *
 * @param     flag:the flag to check.
 *
 * @retval    Flag State
 *
 * @note
 */
uint8_t DMA_ReadFlagState(DMA_FLAG flag)
{
    if((flag & 0x10000000) != RESET )
    {
        if((DMA2->IF & flag ) != RESET )
        {
            return SET ;
        } else
        {
            return RESET ;
        }
    } 
    else
    {
        if((DMA1->IF & flag ) != RESET )
        {
            return SET ;
        } else
        {
            return RESET ;
        }
    }
}

/*!
 * @brief     Clears the DMAx Channely's flags.
 *
 * @param     flag:the flag to Clear.
 *
 * @retval    None
 *
 * @note
 */
void DMA_ClearFlag(DMA_FLAG flag)
{
    if((flag & 0x10000000) != RESET)
    {
        DMA2->IFR = flag;
    } else
    {
        DMA1->IFR = flag;
    }
}

/*!
 * @brief     Read whether the specified DMAx Channely interrupts is set or not.
 *
 * @param     interrupt:nterrupt source to check.
 *
 * @retval    interrupt State
 *
 * @note
 */
uint8_t DMA_ReadIntState(DMA_INT interrupt)
{
    if((interrupt & 0x10000000) != RESET )
    {
        if((DMA2->IF & interrupt ) != RESET )
        {
            return SET ;
        } else
        {
            return RESET ;
        }
    } else
    {
        if((DMA1->IF & interrupt ) != RESET )
        {
            return SET ;
        } else
        {
            return RESET ;
        }
    }
}
/*!
 * @brief     Clears the DMAx Channely's interrupts.
 *
 * @param     flag:the flag to Clear.
 *
 * @retval    None
 *
 * @note
 */
void DMA_ClearIntFlag(DMA_INT interrupt)
{
    if((interrupt & 0x10000000) != RESET)
    {
        DMA2->IFR = interrupt;
    } else
    {
        DMA1->IFR = interrupt;
    }
}
